package com.dliyun.oap.spring.boot.config;

import com.alibaba.fastjson.JSON;
import com.dliyun.oap.framework.OapServlet;
import com.dliyun.oap.framework.impl.*;
import com.dliyun.oap.framework.security.SecurityManager;
import com.dliyun.oap.framework.security.*;
import com.dliyun.oap.framework.service.RouterService;
import com.dliyun.oap.framework.service.RouterServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author stjdydayou
 */
@Slf4j
public class Config {

    @Autowired
    private ExecutorProperties executorProperties;

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private UploadProperties uploadProperties;

    @Autowired
    private ServiceProperties serviceProperties;

    @Bean
    public ServletRegistrationBean<OapServlet> getServletRegistrationBean() {
        ServletRegistrationBean<OapServlet> registrationBean = new ServletRegistrationBean<>(new OapServlet());
        if (StringUtils.isNotBlank(serviceProperties.getServletPath())) {
            registrationBean.addUrlMappings(serviceProperties.getServletPath());
        } else {
            registrationBean.addUrlMappings("/router");
        }
        return registrationBean;
    }

    @Bean("appSecretManager")
    public AppSecretManager appSecretManager() {
        AppSecretManager appSecretManager = new FileBaseAppSecretManager();
        if (securityProperties.getAppSecretManagerClass() != null) {
            appSecretManager = BeanUtils.instantiateClass(securityProperties.getAppSecretManagerClass());
        }
        return appSecretManager;
    }

    @Bean("serviceAccessController")
    public ServiceAccessController serviceAccessController() {
        ServiceAccessController serviceAccessController = new DefaultServiceAccessController();
        if (securityProperties.getServiceAccessControllerClass() != null) {
            serviceAccessController = BeanUtils.instantiateClass(securityProperties.getServiceAccessControllerClass());
        }
        return serviceAccessController;
    }

    @Bean("invokeTimesController")
    public InvokeTimesController invokeTimesController() {
        InvokeTimesController invokeTimesController = new DefaultInvokeTimesController();
        if (securityProperties.getInvokeTimesControllerClass() != null) {
            invokeTimesController = BeanUtils.instantiateClass(securityProperties.getInvokeTimesControllerClass());
        }
        return invokeTimesController;
    }

    @Bean("fileUploadController")
    public FileUploadController fileUploadController() {
        FileUploadController fileUploadController = new DefaultFileUploadController();
        if (securityProperties.getFileUploadControllerClass() != null) {
            fileUploadController = BeanUtils.instantiateClass(securityProperties.getFileUploadControllerClass());
            fileUploadController.setFileTypes(uploadProperties.getFileTypes());
            fileUploadController.setMaxSize(uploadProperties.getFileMaxSize());
        }
        return fileUploadController;
    }

    @Bean("securityManager")
    public SecurityManager securityManager() {
        return new DefaultSecurityManager();
    }

    @Bean("transportSecurity")
    public TransportSecurity transportSecurity() {
        TransportSecurity transportSecurity;
        if (serviceProperties.getTransportSecurityClass() != null) {
            transportSecurity = BeanUtils.instantiateClass(serviceProperties.getTransportSecurityClass());
        } else {
            transportSecurity = new DefaultTransportSecurity();
        }
        return transportSecurity;
    }

    @Bean
    public RouterService initRouterService() {

        if (log.isDebugEnabled()) {
            log.debug("executorProperties>>>>{}", JSON.toJSONString(executorProperties));
            log.debug("securityProperties>>>>{}", JSON.toJSONString(securityProperties));
            log.debug("uploadProperties>>>>{}", JSON.toJSONString(uploadProperties));
            log.debug("serviceProperties>>>>{}", JSON.toJSONString(serviceProperties));
        }
        RouterService routerService = new RouterServiceImpl();
        routerService.setThreadPoolExecutor(this.getThreadPoolExecutor());

        if (executorProperties.getThreadFerryClass() != null) {
            routerService.setThreadFerryClass(executorProperties.getThreadFerryClass());
        }

        if (serviceProperties.getTimeoutSeconds() != null) {
            routerService.setTimeoutSeconds(serviceProperties.getTimeoutSeconds());
        }

        return routerService;
    }


    private ThreadPoolExecutor getThreadPoolExecutor() {

        BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>(executorProperties.getQueueCapacity() == null ? Integer.MAX_VALUE : executorProperties.getQueueCapacity());
        return new ThreadPoolExecutor(executorProperties.getCorePoolSize(), executorProperties.getMaxPoolSize(), executorProperties.getKeepAliveSeconds(), TimeUnit.SECONDS, blockingQueue, new ThreadFactory() {
            private final AtomicInteger atomicInteger = new AtomicInteger();

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "Service Thread: " + atomicInteger.getAndIncrement());
            }
        });

    }
}
